<?php

namespace adminApi\modules\product\controllers;

use adminApi\models\db\SearchKeywords;
use adminApi\models\db\SkuAttrks;
use adminApi\models\db\SkuAttrvs;
use adminApi\models\db\SkuHasAttrvs;
use adminApi\models\db\SpuHasKeywords;
use adminApi\models\db\SpuHasRemoteFreights;
use Carbon\Carbon;
use common\components\fast_api\Controller;
use common\components\wtools\tools\Model;
use common\datas\Enums;
use adminApi\models\db\Skus;
use adminApi\models\db\Spus;
use common\Tools;
use yii\base\Exception;
use yii\helpers\ArrayHelper;

class GoodsController extends Controller
{
    /**
     * 添加或编辑商品
     * @desc json形式提交editForm
     * @param string $editForm
     * @return array
     */
    public function actionAddOrEdit($editForm)
    {
        $editForm = Tools::isJson($editForm);
        $trans = \Yii::$app->db->beginTransaction();
        try {
            // spu
            if ($editForm['id'] > 0) {
                $Spu = Spus::findOne($editForm['id']);
                if (!$Spu) {
                    return $this->apiError('未找到商品');
                }
            } else {
                $Spu = new Spus();
                if ($editForm['copiedById'] > 0) {
                    $Spu->copied_by_id = $editForm['copiedById'];
                }
            }
            $Spu->name = $editForm['spu']['name'];

            $keywords = array_unique($editForm['spu']['keywords']);
            if (count($keywords) > 20) {
                return $this->apiError("关键字不能超过20个！");
            }
            foreach ($keywords as $keyword) {
                if (mb_strlen($keyword) > 50) {
                    return $this->apiError("关键字{$keyword}不能超过50个字符！");
                }
            }

            $Spu->category_id = $editForm['spu']['categoryId'];
            $Spu->supplier_id = $editForm['spu']['supplierId'];
            $Spu->is_virtual = $editForm['spu']['isVirtual'] ? Enums::YES : Enums::NO;
            $Spu->is_second_hand = $editForm['spu']['isSecondHand'] ? Enums::YES : Enums::NO;
            $Spu->freight_price = $editForm['freightInfo']['freightPrice'];
            $Spu->is_present_insurance = $editForm['otherData']['isPresentInsurance'] ? Enums::YES : Enums::NO;
            // salesInfo
            $Spu->sort = $editForm['salesInfo']['sort'] ?? 1;
            $Spu->is_put_on_sale = $editForm['salesInfo']['isPutOnSale'] ? Enums::YES : Enums::NO;
            $Spu->is_auto_put_on_sale = $editForm['salesInfo']['isAutoPutOnSale'] ? Enums::YES : Enums::NO;
            $Spu->is_auto_put_off_sale = $editForm['salesInfo']['isAutoPutOffSale'] ? Enums::YES : Enums::NO;
            $Spu->put_on_sale_begin = Carbon::parse($editForm['salesInfo']['putOnSaleRange'][0])->timestamp;
            $Spu->put_on_sale_end = Carbon::parse($editForm['salesInfo']['putOnSaleRange'][1])->tomorrow()->timestamp - 1;
            $Spu->numbering = Tools::generateHasDateUniqueString();
            if (!$Spu->save()) {
                return $this->apiError('spu保存失败：'.Model::getModelError($Spu));
            } else {
                $Spu->refresh();
                $Spu->numbering = "S".str_pad($Spu->id, 8, '0', STR_PAD_LEFT);
                if ($Spu->id > pow(10, 7) - 1) {
                    $Spu->numbering = "S0".$Spu->id;
                }
                $Spu->save();
                $Spu->refresh();
            }

            // 关键字
            $hasSearchKeywords = [];
            foreach ($keywords as $keyword) {
                $searchKeyword = SearchKeywords::findOne(['keyword' => $keyword]);
                if (!$searchKeyword) {
                    $searchKeyword = new SearchKeywords();
                    $searchKeyword->keyword = $keyword;
                    if (!$searchKeyword->save()) {
                        return $this->apiError('搜索关键字保存失败：'.Model::getModelError($searchKeyword));
                    }
                }
                $HasSearchKeywords = SpuHasKeywords::findOne(['spu_id' => $Spu->id, 'search_keyword_id' => $searchKeyword->id]);
                if (!$HasSearchKeywords) {
                    $HasSearchKeywords = new SpuHasKeywords();
                    $HasSearchKeywords->spu_id = $Spu->id;
                    $HasSearchKeywords->search_keyword_id = $searchKeyword->id;
                    if (!$HasSearchKeywords->save()) {
                        return $this->apiError('spuHas搜索关键字保存失败：'.Model::getModelError($HasSearchKeywords));
                    }
                }
                $hasSearchKeywords[] = $HasSearchKeywords->toArray();
            }
            $Spu->keyword_count = count($keywords);
            if (!$Spu->save()) {
                return $this->apiError('spu保存失败：'.Model::getModelError($Spu));
            }
            Model::syncManyHasManyForce($Spu, SpuHasKeywords::class, 'hasKeywords', $hasSearchKeywords ?? [], 'spu_id');

            // 追加远程运费
            $provinceIds = [];
            foreach ($editForm['freightInfo']['remoteFreights'] as $k => $v) {
                if (!$v['provinceId']) {
                    return $this->apiError("地区未选择");
                }
                if (!$v['appendFreightPrice']) {
                    return $this->apiError("附加运费不能为空");
                }
                $provinceIds[] = $v['provinceId'];
            }
            $provinceIds = array_unique($provinceIds);
            $Spu->append_remote_freight_province_count = count($provinceIds); // 不包邮省ID
            if (!$Spu->save()) {
                return $this->apiError('spu保存失败：'.Model::getModelError($Spu));
            }
            Model::syncManyHasManyForce($Spu, SpuHasRemoteFreights::class, 'remoteFreights', $editForm['freightInfo']['remoteFreights'] ?? [], 'spu_id');

            // attrs
            /** @var SkuAttrks[] $attrKUuidMap */
            $attrKUuidMap = [];
            /** @var SkuAttrvs[] $attrVUuidMap */
            $attrVUuidMap = [];
            foreach ($editForm['attrs'] as $k => $attrK) {
                if (!in_array($attrK['uuid'], array_keys($attrKUuidMap))) {
                    $AttrK = SkuAttrks::findOne(['value' => $attrK['k']]);
                    if (!$AttrK) {
                        $AttrK = new SkuAttrks();
                        $AttrK->value = $attrK['k'];
                        if (!$AttrK->save()) {
                            return $this->apiError('attrK保存失败：'.Model::getModelError($AttrK));
                        }
                    }
                    foreach ($attrK['v'] as $k1 => $attrV) {
                        if (!in_array($attrV['uuid'], array_keys($attrVUuidMap))) {
                            $AttrV = SkuAttrvs::findOne(['sku_attrk_id' => $AttrK->id, 'value' => $attrV['value']]);
                            if (!$AttrV) {
                                $AttrV = new SkuAttrvs();
                                $AttrV->sku_attrk_id = $AttrK->id;
                                $AttrV->value = $attrV['value'];
                                if (!$AttrV->save()) {
                                    return $this->apiError('attrV保存失败：'.Model::getModelError($AttrV));
                                }
                            }
                            $attrVUuidMap[$attrV['uuid']] = $AttrV;
                        }
                    }
                }
                $attrKUuidMap[$attrK['uuid']] = $AttrK;
            }
            // skus
            $hasSkuIds = $addOrEditSkuIds = [];
            foreach ($Spu->skus as $k => $sku) {
                $hasSkuIds[] = $sku->id;
            }
            if (count($editForm['skus']) === 0) {
                return $this->apiError("至少一个sku");
            }
            $spuInventory = 0; // spu总库存
            foreach ($editForm['skus'] as $k => $sku) {
                if ($sku['id'] > 0) {
                    $Sku = Skus::findOne($sku['id']);
                } else {
                    $Sku = new Skus();
                    $Sku->spu_id = $Spu->id;
                    if ($sku['copiedById'] > 0) {
//                        dd($sku['copiedById'], $sku['coverFileId']);
                        $Sku->copied_by_id = $sku['copiedById'];
                    }
                }
                $Sku->sort = $sku['sort'];
                $Sku->cover_file_id = $sku['coverFileId'] ?: null;
                if (!$sku['cover']) { // 删除图片
                    $Sku->cover_file_id = null;
                }
                $Sku->inventory = $sku['inventory'];
                $Sku->cost_price = $sku['costPrice'];
                $Sku->shop_price = $sku['shopPrice'];
                $Sku->sale_price = $sku['salePrice'];
                $Sku->guide_price = $sku['guidePrice'];
                $Sku->commission_price = $sku['commissionPrice'];
                $Sku->reward_price = $sku['rewardPrice'];
                if (!$Sku->save()) {
                    return $this->apiError('sku保存失败：'.Model::getModelError($Sku));
                }
                // spu总库存
                $spuInventory += $Sku->inventory;
                $addOrEditSkuIds[] = $Sku->id;
                // attrs
                $hasAttrVIds = $newAttrVIds = [];
                foreach ($Sku->hasAttrvs as $k1 => $hasAttrv) {
                    /** @var SkuHasAttrvs $hasAttrv */
                    $hasAttrVIds[] = $hasAttrv->attrv_id;
                }
                foreach ($sku['vUuids'] as $k1 => $vUuid) {
                    $newAttrVIds[] = $attrVUuidMap[$vUuid]->id;
                }
                $hasToDelAttrVIds = array_diff($hasAttrVIds, $newAttrVIds);
                $hasToAddAttrVIds = array_diff($newAttrVIds, $hasAttrVIds);
                if (count($hasToDelAttrVIds) == count($hasToAddAttrVIds)) {
                    if (count($hasToDelAttrVIds) > 0) {
                        $hasToDelAttrVIds = array_values($hasToDelAttrVIds);
                        $hasToAddAttrVIds = array_values($hasToAddAttrVIds);
                        foreach ($hasToDelAttrVIds as $k1 => $v1) {
                            $toEditHasAttrv = SkuHasAttrvs::findOne(['sku_id' => $Sku->id, 'attrv_id' => $v1]);
                            $toEditHasAttrv->attrv_id = $hasToAddAttrVIds[$k1];
                            if (!$toEditHasAttrv->save()) {
                                return $this->apiError('skuHasAttrv修改失败：'.Model::getModelError($toEditHasAttrv));
                            }
                        }
                    }
                } else {
                    if (count($hasToDelAttrVIds) > 0) {
                        SkuHasAttrvs::deleteAll(['and', ['sku_id' => $Sku->id], ['attrv_id' => $hasToDelAttrVIds]]);
                    }
                    if (count($hasToAddAttrVIds) > 0) {
                        foreach ($hasToAddAttrVIds as $k1 => $attrVId) {
                            $HasAttrv = new SkuHasAttrvs();
                            $HasAttrv->spu_id = $Spu->id;
                            $HasAttrv->sku_id = $Sku->id;
                            $HasAttrv->attrv_id = $attrVId;
                            if (!$HasAttrv->save()) {
                                return $this->apiError('skuHasAttrv添加失败：'.Model::getModelError($HasAttrv));
                            }
                        }
                    }
                }
            }
            // spu总库存更新
            $Spu->inventory = $spuInventory;
            if (!$Spu->save()) {
                return $this->apiError('spu保存失败：'.Model::getModelError($Spu));
            }
            // 删除已存在的sku
            $toRmSkuIds = array_diff($hasSkuIds, $addOrEditSkuIds);
            if (count($toRmSkuIds) > 0) {
                Skus::deleteAll(['and', ['spu_id' => $Spu->id], ['id' => $toRmSkuIds]]);
                SkuHasAttrvs::deleteAll(['sku_id' => $toRmSkuIds]);
            }
            // 刷新spu
            if (Skus::find()->andWhere(['spu_id' => $Spu->id])->count() === 0) {
                return $this->apiError('sku数量不能为0');
            }
            $trans->commit();
        } catch (Exception $e) {
            $trans->rollBack();
            return $this->apiError('保存失败：'.$e->getMessage());
        }
        return $this->apiSuccess([
            'id' => $Spu->id,
            'editForm' => $editForm,
        ]);
    }

    /**
     * 商品详细
     * @desc 商品详细
     * @param int $id
     * @return array
     */
    public function actionInfo($id)
    {
        $Spu = Spus::find()
            ->with(['category', 'supplier', 'remoteFreights.province', 'skus' => function($builder) {
                $builder->with(['hasAttrvs.skuAttrv.skuAttrk', 'coverFile']);
            }, 'hasKeywords.searchKeyword'])
            ->where(['id' => $id])
            ->one();
        $_spu = $Spu->toArray();
        $_spu['_status'] = Enums::getStatusDesc()[$Spu->status];
//        $_spu['_categoryChains'] = $Spu->category->nodeChains();
        $nodeChainIds = $nodeChainNames = [];
        foreach ($Spu->category->nodeChains() as $nodeChain) {
            $nodeChainIds[] = $nodeChain->id;
            $nodeChainNames[] = $nodeChain->name;
        }
        $_spu['_categoryChainIds'] = implode('-', $nodeChainIds);
        $_spu['_categoryChainName'] = implode('-', $nodeChainNames);
        $_spu['_supplierNameMobile'] = $Spu->supplier?$Spu->supplier->mobile.' | '.$Spu->supplier->name:'';
        $_spu['_putOnSaleRange'] = [
            Carbon::parse($Spu->put_on_sale_begin)->format('Y-m-d H:i'),
            Carbon::parse($Spu->put_on_sale_end)->format('Y-m-d H:i'),
        ];
        $_spu['_remoteFreights'] = $_spu['_keywords'] = [];
        foreach ($Spu->remoteFreights as $k => $v) {
            $remoteFreight = [];
            $remoteFreight['id'] = $v->id;
            $remoteFreight['uuid'] = str_replace('\\', '-', $v::class).'-'.$v->id;
            $remoteFreight['provinceId'] = $v->province_id;
            $remoteFreight['appendFreightPrice'] = $v->append_freight_price;
            $remoteFreight['_province'] = $v->province->toArray();
            $remoteFreight['_provinceName'] = $v->province->name;
            $_spu['_remoteFreights'][] = $remoteFreight;
        }
        foreach ($Spu->hasKeywords as $hasKeyword) {
            $_spu['_keywords'][] = $hasKeyword->searchKeyword->keyword;
        }
        $skus = $attrs = [];
        foreach ($Spu->skus as $k => $sku) {
            /** @var Skus $sku */
            $_sku['id'] = $sku->id;
            $_sku['key'] = str_replace('\\', '-', $sku::class).'-'.$sku->id;
            $_sku['vUuids'] = $_sku['vIds'] = [];
            foreach ($sku->hasAttrvs as $k1 => $hasAttrv) {
                /** @var SkuHasAttrvs $hasAttrv */
                $skuAttrv = $hasAttrv->skuAttrv;
                $skuAttrk = $skuAttrv->skuAttrk;
                $_sku['vIds'][] = $skuAttrv->id;
                $vUuid = str_replace('\\', '-', SkuAttrvs::class).'-'.$skuAttrv->id;
                $_sku['vUuids'][] = $vUuid;
                $vkUuid = str_replace('\\', '-', SkuAttrks::class).'-'.$skuAttrk->id;
                $_attrK = [
                    'id' => $skuAttrk->id,
                    'uuid' => $vkUuid,
                    'isEdit' => false,
                    'selVCount' => 0,
                    'vEditingCount' => 0,
                    'k' => $skuAttrk->value,
                ];
                $_attrV = [
                    'id' => $skuAttrv->id,
                    'uuid' => $vUuid,
                    'isEdit' => false,
                    'isSel' => false,
                    'value' => $skuAttrv->value,
                ];
                $_sku[$vkUuid] = [
                    'attrK' => $_attrK,
                    'attrV' => $_attrV,
                ];
                $tmp = $attrs[$vkUuid]['v'] ?? [];
                $attrs[$vkUuid] = $_attrK;
                $tmp[$vUuid] = $_attrV;
                $attrs[$vkUuid]['v']= $tmp;
            }
            if ($sku->cover_file_id) {
                $_sku['coverFileId'] = $sku->cover_file_id;
                $_sku['cover'] = $sku->coverFile->abUrl;
            } else {
                $_sku['coverFileId'] = null;
                $_sku['cover'] = null;
            }
            $_sku['isSel'] = false;
            $_sku['copiedById'] = $sku->copied_by_id;
            $_sku['sort'] = $sku->sort;
            $_sku['inventory'] = $sku->inventory;
            $_sku['costPrice'] = $sku->cost_price;
            $_sku['shopPrice'] = $sku->shop_price;
            $_sku['salePrice'] = $sku->sale_price;
            $_sku['guidePrice'] = $sku->guide_price;
            $_sku['commissionPrice'] = $sku->commission_price;
            $_sku['rewardPrice'] = $sku->reward_price;
            $_sku['salesVolume'] = $sku->sales_volume;
            $skus[] = $_sku;
        }
        $_attrs = [];
        foreach ($attrs as $k => $attr) {
            $_v = [];
            foreach ($attr['v'] as $k1 => $v) {
                $_v[] = $v;
            }
            $attr['v'] = $_v;
            $_attrs[] = $attr;
        }
        return $this->apiSuccess([
            'spu' => $_spu,
            'skus' => $skus,
            'attrs' => $_attrs,
        ]);
    }

    /**
     * 列表
     * @desc 商品列表
     * @param int $page 页码
     * @param int $pageSize 每页条数
     * @param string|null $name 商品名
     * @param int $status 状态
     * @return mixed
     * @throws \yii\base\InvalidConfigException
     */
    public function actionList(int $page = 1, int $pageSize = 10, string $name = null, int $status = null)
    {
        $query = Spus::find();
        if ($name) {
            $query->andFilterWhere(['like', 'name', $name]);
        }
        if ($status) {
            $query->andFilterWhere(['status' => $status]);
        }
        $apiPageData = $this->apiPageData($query, $page, $pageSize);
        $items = [];
        foreach ($apiPageData->dataProvider->models as $k => $v) {
            /** @var Spus $v */
            $m = [];
            $m['id'] = $v->id;
            $m['numbering'] = $v->numbering;
            $m['name'] = $v->name;
            $m['created_at'] = $v->created_at;
            $m['_created_at'] = date("Y-m-d H:i", $v->created_at);
            $m['status'] = $v->status;
            $m['_status'] = Enums::getStatusDesc()[$v->status];
            $m['is_put_on_sale'] = $v->is_put_on_sale;
            $m['_is_put_on_sale'] = Enums::getIsDesc()[$v->is_put_on_sale];
            $m['is_auto_put_on_sale'] = $v->is_auto_put_on_sale;
            $m['_is_auto_put_on_sale'] = Enums::getIsDesc()[$v->is_auto_put_on_sale];
            $m['is_auto_put_off_sale'] = $v->is_auto_put_off_sale;
            $m['_is_auto_put_off_sale'] = Enums::getIsDesc()[$v->is_auto_put_off_sale];
            $items[] = $m;
        }
        $data = [
            'items' => $items,
            '_meta' => $apiPageData->meta,
        ];
        return $this->apiSuccess($data, '获取列表成功');
    }
}
